﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using l1cs.server.templates;
using MySql.Data.MySqlClient;
using System.Data;
using l1cs.server.model.Instance;
using l1cs.server.utils;

namespace l1cs.server.datatables
{
    public class MailTable
    {
        private static Logger _log = Logger.getLogger( typeof( MailTable ).FullName );

        private static MailTable _instance;

        private static List<L1Mail> _allMail = new List<L1Mail>();

        public static MailTable getInstance()
        {
            if ( _instance == null )
            {
                _instance = new MailTable();
            }
            return _instance;
        }

        private MailTable()
        {/*TTOK*/
            String sqlstr = "SELECT * FROM mail";
            using ( MySqlWrapper wrapper = new MySqlWrapper() )
            {
                foreach ( DataRow item in wrapper.GetDataTable( sqlstr ).Rows )
                {
                    L1Mail mail = new L1Mail();
                    mail.setId( SqlUtils.toInt( item["id"] ) );
                    mail.setType( SqlUtils.toInt( item["type"] ) );
                    mail.setSenderName( Convert.ToString( item["sender"] ) );
                    mail.setReceiverName( Convert.ToString( item["receiver"] ) );
                    mail.setDate( Convert.ToString( item["date"] ) );
                    mail.setReadStatus( SqlUtils.toInt( item["read_status"] ) );
                    mail.setSubject( (byte[])item["subject"] );
                    mail.setContent( (byte[])item["content"] );

                    _allMail.Add( mail );
                }
            }
        }

        /// <summary>
        /// 便箋ステータスをDBに反映する。
        /// </summary>
        /// <param name="mailId"></param>
        public void setReadStatus( int mailId )
        {/*TTOK*/
            String sqlstr = "SELECT * FROM mail WHERE id = ?1";
            using ( MySqlWrapper wrapper = new MySqlWrapper() )
            {
                MySqlCommand cmd = new MySqlCommand( sqlstr );
                cmd.Parameters.Add( "?1", MySqlDbType.Int32 ).Value = mailId;
                DataTable dt = wrapper.GetDataTable( cmd );
                if ( dt.Rows.Count == 1 )
                {
                    sqlstr = "UPDATE mail SET read_status=1 WHERE id = ?1";
                    MySqlCommand cmd2 = new MySqlCommand( sqlstr );
                    cmd2.Parameters.Add( "?1", MySqlDbType.Int32 ).Value = mailId;
                    wrapper.ExecNonQuery( cmd2 );

                    changeMailStatus( mailId );
                }
            }
        }

        /// <summary>
        /// 便箋状態をDBに反映する。
        /// </summary>
        /// <param name="mailId"></param>
        /// <param name="type"></param>
        public void setMailType( int mailId, int type )
        {/*TTOK*/
            String sqlstr = "SELECT * FROM mail WHERE id = ?1";
            using ( MySqlWrapper wrapper = new MySqlWrapper() )
            {
                MySqlCommand cmd = new MySqlCommand( sqlstr );
                cmd.Parameters.Add( "?1", MySqlDbType.Int32 ).Value = mailId;
                DataTable dt = wrapper.GetDataTable( cmd );
                if ( dt.Rows.Count == 1 )
                {
                    sqlstr = String.Format( "UPDATE mail SET type=?1 WHERE id=?2" );
                    MySqlCommand cmd2 = new MySqlCommand( sqlstr );
                    cmd2.Parameters.Add( "?1", MySqlDbType.Int32 ).Value = type;
                    cmd2.Parameters.Add( "?2", MySqlDbType.Int32 ).Value = mailId;
                    wrapper.ExecNonQuery( cmd2 );

                    changeMailType( mailId, type );
                }
            }
        }

        /// <summary>
        /// 便箋情報をDBから削除する。
        /// </summary>
        /// <param name="mailId"></param>
        public void deleteMail( int mailId )
        {
            String sqlstr = "DELETE FROM mail WHERE id = ?1";
            using ( MySqlWrapper wrapper = new MySqlWrapper() )
            {
                MySqlCommand cmd = new MySqlCommand( sqlstr );
                cmd.Parameters.Add( "?1", MySqlDbType.Int32 ).Value = mailId;
                wrapper.ExecNonQuery( cmd );
            }
            delMail( mailId );
        }

        /// <summary>
        /// 便箋情報をDBに追加する。
        /// </summary>
        /// <param name="type"></param>
        /// <param name="receiver"></param>
        /// <param name="writer"></param>
        /// <param name="text"></param>
        public void writeMail( int type, String receiver, L1PcInstance writer, byte[] text )
        {/*TTOK*/
            int readStatus = 0;
            String date = DateTime.Now.ToString( "yy/MM/dd" );

            // subjectとcontentの区切り(0x00 0x00)位置を見つける
            int spacePosition1 = 0;
            int spacePosition2 = 0;
            for ( int i = 0; i < text.Length; i += 2 )
            {
                if ( text[i] == 0 && text[i + 1] == 0 )
                {
                    if ( spacePosition1 == 0 )
                    {
                        spacePosition1 = i;
                    }
                    else if ( spacePosition1 != 0 && spacePosition2 == 0 )
                    {
                        spacePosition2 = i;
                        break;
                    }
                }
            }

            // mailテーブルに書き込む
            int subjectLength = spacePosition1 + 2;
            int contentLength = spacePosition2 - spacePosition1;
            if ( contentLength <= 0 )
            {
                contentLength = 1;
            }
            byte[] subject = new byte[subjectLength];
            byte[] content = new byte[contentLength];
            System.Array.Copy( text, 0, subject, 0, subjectLength );
            System.Array.Copy( text, subjectLength, content, 0, contentLength );
            int id = IdFactory.getInstance().nextId();

            String sqlstr = "INSERT INTO mail SET " +
                            "id          = ?1, " +
                            "type        = ?2, " +
                            "sender      = ?3, " +
                            "receiver    = ?4," +
                            "date        = ?5, " +
                            "read_status = ?6, " +
                            "subject     = ?7, " +
                            "content     = ?8";
            using ( MySqlWrapper wrapper = new MySqlWrapper() )
            {
                MySqlCommand cmd = new MySqlCommand( sqlstr );
                cmd.Parameters.Add( "?1", MySqlDbType.Int32 ).Value = id;
                cmd.Parameters.Add( "?2", MySqlDbType.Int32 ).Value = type;
                cmd.Parameters.Add( "?3", MySqlDbType.String ).Value = writer.getName();
                cmd.Parameters.Add( "?4", MySqlDbType.String ).Value = receiver;
                cmd.Parameters.Add( "?5", MySqlDbType.String ).Value = date;
                cmd.Parameters.Add( "?6", MySqlDbType.Int32 ).Value = readStatus;
                cmd.Parameters.Add( "?7", MySqlDbType.Blob ).Value = subject;
                cmd.Parameters.Add( "?8", MySqlDbType.Blob ).Value = content;
                wrapper.ExecNonQuery( cmd );
            }

            L1Mail mail = new L1Mail();
            mail.setId( id );
            mail.setType( type );
            mail.setSenderName( writer.getName() );
            mail.setReceiverName( receiver );
            mail.setDate( date );
            mail.setSubject( subject );
            mail.setContent( content );
            mail.setReadStatus( readStatus );

            _allMail.Add( mail );

        }

        /// <summary>
        /// 全ての便箋情報を返す。
        /// </summary>
        /// <returns></returns>
        public static List<L1Mail> getAllMail()
        {/*TTOK*/
            return _allMail;
        }

        /// <summary>
        /// 便箋情報を返す。
        /// </summary>
        /// <param name="mailId"></param>
        /// <returns></returns>
        public static L1Mail getMail( int mailId )
        {/*TTOK*/
            foreach ( L1Mail mail in _allMail )
            {
                if ( mail.getId() == mailId )
                {
                    return mail;
                }
            }
            return null;
        }

        /// <summary>
        /// 内部データの便箋ステータスを変更する。
        /// </summary>
        /// <param name="mailId"></param>
        private void changeMailStatus( int mailId )
        {/*TTOK*/
            foreach ( L1Mail mail in _allMail )
            {
                if ( mail.getId() == mailId )
                {
                    L1Mail newMail = mail;
                    newMail.setReadStatus( 1 );

                    _allMail.Remove( mail );
                    _allMail.Add( newMail );
                    break;
                }
            }
        }

        /// <summary>
        /// 内部情報から便箋タイプを変更する。
        /// </summary>
        /// <param name="mailId"></param>
        /// <param name="type"></param>
        private void changeMailType( int mailId, int type )
        {/*TTOK*/
            foreach ( L1Mail mail in _allMail )
            {
                if ( mail.getId() == mailId )
                {
                    L1Mail newMail = mail;
                    newMail.setType( type );

                    _allMail.Remove( mail );
                    _allMail.Add( newMail );
                    break;
                }
            }
        }

        /// <summary>
        /// 内部配列から便箋情報を削除する。
        /// </summary>
        /// <param name="mailId"></param>
        private void delMail( int mailId )
        {/*TTOK*/
            foreach ( L1Mail mail in _allMail )
            {
                if ( mail.getId() == mailId )
                {
                    _allMail.Remove( mail );
                    break;
                }
            }
        }
    }
}
